package net.itxxw.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import net.itxxw.framework.domain.cms.CmsConfig;
import net.itxxw.framework.domain.cms.CmsPage;
import net.itxxw.framework.domain.cms.CmsSite;
import net.itxxw.framework.domain.cms.CmsTemplate;
import net.itxxw.framework.domain.cms.request.QueryPageRequest;
import net.itxxw.framework.domain.cms.response.CmsCode;
import net.itxxw.framework.domain.cms.response.CmsPageResult;
import net.itxxw.framework.domain.cms.response.CmsPostPageResult;
import net.itxxw.framework.domain.system.SysDictionary;
import net.itxxw.framework.exception.ExceptionCast;
import net.itxxw.framework.model.response.CommonCode;
import net.itxxw.framework.model.response.QueryResponseResult;
import net.itxxw.framework.model.response.QueryResult;
import net.itxxw.framework.model.response.ResponseResult;
import net.itxxw.manage_cms.config.RabbitmqConfig;
import net.itxxw.manage_cms.dao.*;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;


@Service
public class PageService {
    @Autowired
    CmsPageRepository cmsPageRepository;

    @Autowired
    CmsConfigRepository cmsConfigRepository;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    CmsTemplateRepository cmsTemplateRepository;

    @Autowired
    GridFsTemplate gridFsTemplate;

    @Autowired
    GridFSBucket gridFSBucket;

    @Autowired
    CmsConfigService cmsConfigService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    CmsSysDictionaryRespository cmsSysDictionaryRespository;
    @Autowired
    CmsSiteRepository cmsSiteRepository;

    /**
     * 页面列表分页查询
     * @param page 当前页码
     * @param size 页面显示个数
     * @param queryPageRequest 查询条件
     * @return 页面列表
     */
    public QueryResponseResult findCmsPageList(int page, int size,  QueryPageRequest queryPageRequest) {

        //判断传进来的页面，小于第一页，就默认查询第一页
        if (page <= 0){
            page = 1;
        }
        //如果传进来的不是小于0，证明页面正确，就-1，因为数据库是从0开始，
        page = page - 1;

        //判断传进来的显示数量，小于10，就默认查询10条
        if (size <= 0){
            size = 10;
        }
        //组装查询所需要的页码和数量，的pageable对象
        Pageable pageable = PageRequest.of(page,size);
        //__________分页信息组装好后，开始组装条件查询_____________

        //**开始**提前准备一个空的条件查询对象
        Example<CmsPage> example = null;

        //****先判断，条件查询的对象是否为空,不为空，才开始组装查询条件****
        if (queryPageRequest!=null){
            //先准备一个cms分页对象。
            CmsPage cmsPage = new CmsPage();

            //如果站点id，不为空，就组装cms对象
            String siteId = queryPageRequest.getSiteId();
            if (siteId!=null && !siteId.equals("")){
                cmsPage.setSiteId(siteId);
            }

            //如果站点模板id，不为空，就组装cms对象
            String TemplateId = queryPageRequest.getTemplateId();
            if (TemplateId!=null && !TemplateId.equals("")){
                cmsPage.setTemplateId(TemplateId);
            }

            //如果别名，不为空，就组装cms对象
            String PageAliase = queryPageRequest.getPageAliase();
            if (PageAliase!=null && !PageAliase.equals("")){
                cmsPage.setPageAliase(PageAliase);
            }

            //别名属于模糊查询，所以需要，设置模糊条件查询匹配器
            //ExampleMatcher.GenericPropertyMatchers.contains() 包含关键字
            //ExampleMatcher.GenericPropertyMatchers.startsWith() 前缀匹配
            ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                    //链式点出，通过关键字匹配，数据库中的PageAliase列
                    .withMatcher("pageAliase",ExampleMatcher.GenericPropertyMatchers.contains());
            //把组装好的cms条件查询对象和模糊条件匹配器，
            // 添加进条件查询的静态方法中。得到一个条件查询对象
            example = Example.of(cmsPage,exampleMatcher);
        }

//********分页信息组装好后，开始组装条件查询结束********

        //执行查询,参数1,条件查询的对象，参数2，分页参数值对象
        Page<CmsPage> cmsPagePageList = cmsPageRepository.findAll(example,pageable);
        System.err.println(cmsPagePageList.getContent());
        //封装分页数据集合和总记录数的对象
        QueryResult queryResult = new QueryResult();
        //得到分页数据集合
        queryResult.setList(cmsPagePageList.getContent());
        // 得到总记录数
        queryResult.setTotal(cmsPagePageList.getTotalElements());
        //封装返回到页面的固定格式对象
        QueryResponseResult queryResponseResult =
                new QueryResponseResult(CommonCode.SUCCESS,queryResult);
        return queryResponseResult;
    }



    //_________新增页面方法，
    public CmsPageResult addCmsPage(CmsPage cmsPage){

        if (cmsPage == null) {
            //证明进来的参数没有，也就是参数异常
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }

        //进来的对象，不为空，就执行校验
        CmsPage page = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath
                (cmsPage.getPageName(),cmsPage.getSiteId(),cmsPage.getPageWebPath());
        if (page == null) {
            //如果校验没有这个页面，就执行添加页面的操作
            //添加页面之前，先把页面id,清除，让MongoDB数据库自己生成主键
            cmsPage.setPageId(null);
            //执行添加页面的操作
            CmsPage cmsPage1 = cmsPageRepository.save(cmsPage);
            //返回resultful规范数据
            return new CmsPageResult(CommonCode.SUCCESS,cmsPage1);
        }
        //如果校验到了，就直接不让新增
        ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
        //返回一个null,防止语法报错，前面的异常会拦截，下面是不可达代码
        return null;
    }


    //根据id查询页面  单查回显
     public CmsPage findCmsPageById(String id){
         Optional<CmsPage> optional = cmsPageRepository.findById(id);
          if(optional.isPresent()){
              return optional.get();
          }
          return  null;
     }

     //更新页面信息  //修改操作，包括，数据单查回显，数据修改2个方法
     public CmsPageResult updateCmsPage(String id,CmsPage cmsPage){
        //根据ID查询页面信息
         CmsPage one=this.findCmsPageById(id);
         if(one!=null){
             //更新模板id
             one.setTemplateId(cmsPage.getTemplateId());
             //更新所属站点
             one.setSiteId(cmsPage.getSiteId());
             //更新页面别名
             one.setPageAliase(cmsPage.getPageAliase());
             //更新页面名称
             one.setPageName(cmsPage.getPageName());
              //更新访问路径
             one.setPageWebPath(cmsPage.getPageWebPath());
              //更新物理路径
             one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
             //更新dataURI
             one.setDataUrl(cmsPage.getDataUrl());
             //执行更新
             CmsPage save = cmsPageRepository.save(one);
             if(save!=null){
                 //返回成功
                 CmsPageResult cmsPageResult = new CmsPageResult(CommonCode.SUCCESS, save);
                 return cmsPageResult ;
             }
         }
         //返回失败
          return new CmsPageResult(CommonCode.FAIL,null);
     }

     //删除页面
    public ResponseResult delete(String id){
        CmsPage one = this.findCmsPageById(id);
        if(one!=null){
          //删除页面
          cmsPageRepository.deleteById(id);
          return new ResponseResult(CommonCode.SUCCESS);
        }
        return new ResponseResult(CommonCode.FAIL);
    }

   //根据id查询cmsConfig
    public  CmsConfig getConfigById(String id){
        Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
        if(optional.isPresent()){
            CmsConfig cmsConfig = optional.get();
            return  cmsConfig;
        }
        return null;
    }


    //页面发布
    public ResponseResult post(String pageId) {

        //System.out.println("运行到此处啦");

        //执行静态化
        String pageHtml = null;
        try {
            pageHtml = this.cmsConfigService.getPageHtml(pageId);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        if(StringUtils.isEmpty(pageHtml)){
            ExceptionCast.cast(CmsCode.CMS_GENRATEHTML_HTML_IS_NULL);
        }




        //将页面静态化文件存储到GridFS中
        CmsPage cmsPage = saveHtml(pageId, pageHtml);
        //给Mq发消息，喊他，可以去下载页面到，本地客户端的目录下了
        this.sendPostPage(pageId);
        return new ResponseResult(CommonCode.SUCCESS);
    }


    //向MQ发送消息
      private void sendPostPage(String pageId){
        //得到页面信息
          CmsPage cmsPage = this.findCmsPageById(pageId);
          if(cmsPage==null){
              ExceptionCast.cast(CommonCode.INVALID_PARAM);
          }
        //创建消息对象
          Map<String,String> msg=new HashMap<>();
          //存页面id
          msg.put("pageId",pageId);
          ////把map转为json字符串发送
          String jsonString = JSON.toJSONString(msg);
          //发送给mq
          //站点id
          String siteId = cmsPage.getSiteId();
          //发送消息给交换机,交换机，站点id,消息内容
          rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,siteId,jsonString);
      }


    //往gridFs文件管理器中，存静态化好的html方法
    public CmsPage  saveHtml(String pageId,String htmlContent){
          //查询要更新哪个cmsPage页面
        CmsPage cmsPage = this.findCmsPageById(pageId);
         if(cmsPage==null){
             ExceptionCast.cast(CommonCode.INVALID_PARAM);
         }
        //存静态页面，先把字符串页面转换为输入流
        ObjectId objectId=null;
        try {
            //将htmlContent内容转成输入流
            InputStream inputStream = IOUtils.toInputStream(htmlContent, "utf-8");
            //将html文件内容保存到GridFS
            //通过grid模板，存输入流，页面名称存进去，取得自动生成的静态页面的id，类型为object
           objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        } catch (IOException e) {
            e.printStackTrace();
        }

        //将html文件id更新到cmsPage中
        cmsPage.setHtmlFileId(objectId.toHexString());
        cmsPageRepository.save(cmsPage);
        //最后在把已经更新过FileId列id的对象进行返回
        return  cmsPage;
    }

    //查询课程等级，传进来的是课程的等级代码，如课程是200
    public SysDictionary findSysDictionary(String type){
        SysDictionary byDType = cmsSysDictionaryRespository.findByDType(type);
        return byDType;
    }


    //保存页面
    public CmsPageResult saveCmsPage(CmsPage cmsPage) {
        //先通过唯一索引，判断，有没有这个页面
        CmsPage cmsPage1 =
                cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath
                        (cmsPage.getPageName(),cmsPage.getSiteId(),cmsPage.getPageWebPath());
        //如果有这个页面，执行更新
        if (cmsPage1 != null) {
            CmsPageResult edit = this.updateCmsPage(cmsPage1.getPageId(), cmsPage);
            System.err.println(edit.getCmsPage());
            return edit;
        }
        //如果没有，就执行新增
        CmsPageResult add = this.addCmsPage(cmsPage);

        System.err.println(add.getCmsPage());
        return add;
    }

    //一键发布的功能
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
        //将页面信息存储到cms_page 集合中
        CmsPageResult save = this.saveCmsPage(cmsPage);
        if(!save.isSuccess()){
            ExceptionCast.cast(CommonCode.FAIL);
        }
        //得到页面的id
        CmsPage cmsPageSave = save.getCmsPage();
        String pageId = cmsPageSave.getPageId();

        //执行页面发布（先静态化、保存GridFS，向MQ发送消息）
        ResponseResult post = this.post(pageId);
        if(!post.isSuccess()){
            ExceptionCast.cast(CommonCode.FAIL);
        }
        //拼接页面Url= cmsSite.siteDomain+cmsSite.siteWebPath+ cmsPage.pageWebPath + cmsPage.pageName
        //取出站点id
        String siteId = cmsPageSave.getSiteId();
        CmsSite cmsSite = this.findCmsSiteById(siteId);
        //页面url
        String pageUrl =cmsSite.getSiteDomain() + cmsSite.getSiteWebPath() + cmsPageSave.getPageWebPath() + cmsPageSave.getPageName();
        return new CmsPostPageResult(CommonCode.SUCCESS,pageUrl);
    }

    //根据站点id查询站点信息
    public CmsSite findCmsSiteById(String siteId){
        Optional<CmsSite> optional =cmsSiteRepository.findById(siteId);

        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }


}
